#pragma once

#include <stdarg.h>
#include <string>

#include <ace/Task.h>
#include <ace/Log_Msg.h>

#ifdef _WIN32
#include <d3d9.h>
#endif

namespace Tool
{
	enum Exception {EX_ERROR, EX_FATAL};

	enum LogLevel {LG_DEBUG, LG_INFO, LG_WARNING, LG_ERROR, LG_FATAL};

    class Logger
	{
	private:
		static const unsigned int MAX_LOG_DESCRIPTION;

		std::string      m_program;

		std::string      stripLeadingPath(const std::string& p_fileName);


	public:
		Logger();
		~Logger();

        void log(LogLevel p_level, const char* p_file, const char* p_function, unsigned long p_line, ...);

		std::string getProgramName() const;
		void		setProgramName(std::string p_name);

#ifdef _WIN32
#ifdef _DIRECT3D9
		std::string getD3DErrorString(HRESULT p_input) const;
#endif
#endif

	};


   /**
     * @brief copy-paste from ACE book, used to do call tracing
     * @author ACE guy
     */
     // must be in-line, because of contextual tags that depends on the file where
     // it's included
     class Trace
     {
         private:
             enum { nesting_indent_ = 2 }; // indent size

             const ACE_TCHAR *prefix_;
             const ACE_TCHAR *name_;
             const ACE_TCHAR *file_;
			 const ACE_TCHAR *func_;

             int line_;

         public:
			 Trace (const ACE_TCHAR *prefix, const ACE_TCHAR *name, const ACE_TCHAR *func, int line, const ACE_TCHAR *file);             

             void setLine (int line);

             ~Trace (void);        

     }; // end Tracer


};


// copy paste from ACE book
#define TRACE_PREFIX       ACE_TEXT ("TRACE ")

//#if (ACE_NTRACE == 1)
//#    define TRACE(X)
//#    define TRACE_RETURN(V)
//#    define TRACE_RETURN_VOID()
//#else
#    define TRACE(X)                           \
                   ::Tool::Trace ____ (TRACE_PREFIX,          \
                   ACE_TEXT (X),          \
				   ACE_TEXT (__FUNCTION__), \
                   __LINE__,              \
                   ACE_TEXT (__FILE__))

#    define TRACE_RETURN(V)                    \
                   do { ____.setLine(__LINE__); return V; } while (0)

#    define TRACE_RETURN_VOID()                \
                   do { ____.setLine(__LINE__); } while (0)
//#endif



#ifdef LINUX
#define LOGGING(LG_LEVEL, args...) ::Tool::Singulator< ::Tool::Logger>::content().log(LG_LEVEL, __FILE__, __FUNCTION__, __LINE__, args)
#ifdef _DEBUG
#define LOGDEBUG( args... ) LOGGING(::Tool::LG_DEBUG, args)
#else
#define LOGDEBUG( args... )
#endif
#define LOGWARNING( args... ) LOGGING(::Tool::LG_WARNING, args)
#define LOGERROR( args... ) LOGGING(::Tool::LG_ERROR, args)
#define LOGINFO( args... ) LOGGING(::Tool::LG_INFO, args)
#define LOGFATAL( args... ) LOGGING(::Tool::LG_FATAL, args)
#endif

#ifdef WIN32
#define LOGGING( LG_LEVEL, ... ) ::Tool::Singulator<::Tool::Logger>::content().log(LG_LEVEL, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__ )

#ifdef _DEBUG
#define LOGDEBUG( ... ) LOGGING(::Tool::LG_DEBUG, __VA_ARGS__ )
#else
#define LOGDEBUG( ... )
#endif

#define LOGWARNING( ... ) LOGGING(::Tool::LG_WARNING, __VA_ARGS__ )
#define LOGERROR( ... ) LOGGING(::Tool::LG_ERROR, __VA_ARGS__ )
#define LOGINFO( ... ) LOGGING(::Tool::LG_INFO, __VA_ARGS__ )
#define LOGFATAL( ... ) LOGGING(::Tool::LG_FATAL, __VA_ARGS__ )

#endif


#ifdef _DEBUG
#define TRACING( COMMENT ) TRACE(ACE_TEXT(COMMENT))
#else
#define TRACING( COMMENT )
#endif


